﻿
using AutoMapper;

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Lucene.Net.Analysis.PanGu;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Lucene.Net.Util;
using Lucene_PanGu.Common;

using Microsoft.AspNetCore.Mvc;
using PanGu;
using Directory = System.IO.Directory;
using iTextSharp;
using iTextSharp.text;
using iTextSharp.text.pdf;
using Document = Lucene.Net.Documents.Document;
using iTextSharp.text.pdf.parser;
using Field = Lucene.Net.Documents.Field;
//using Spire.Doc;
//using Spire.Doc.Documents;





using Section = Spire.Doc.Section;
using Paragraph = Spire.Doc.Documents.Paragraph;
using Spire.Presentation;
using Spire.Xls;
using System.Data;
using Microsoft.AspNetCore.Hosting;

using Ccteg.Common;
using Ccteg.DB;
using Ccteg.Common.Rbac.Lucene_PanGu;
using Ccteg.Common.Lucene_PanGu;

namespace Cctegaq.Api.Controllers.Api.V1.Rbac
{
    /// <summary>
    /// Lucene文档搜索
    /// </summary>
    [Route("api/v1/rbac/[controller]/[action]")]
    [ApiController]
    // [CustomAuthorize]
    public class LuceneFileController : Controller
    {
        private readonly MySqlDbContext _dbContext;
        private readonly IMapper _mapper;
        private IHostingEnvironment _host = null;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dbContext"></param>
        /// <param name="mapper"></param>
        public LuceneFileController(MySqlDbContext dbContext, IMapper mapper, IHostingEnvironment host)
        {
            _dbContext = dbContext;
            _mapper = mapper;
            _host = host;
        }

        /// <summary>
        /// 创建索引
        /// </summary>
        /// <returns></returns>
        [HttpPost]
       
        public IActionResult CreateIndex()
        {
            var response = ResponseModelFactory.CreateInstance;

            
            //  return Ok(response);

            //索引保存位置
            var indexPath = Directory.GetCurrentDirectory() + "/LuceneIndex";
            if (!Directory.Exists(indexPath)) Directory.CreateDirectory(indexPath);
            FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NativeFSLockFactory());
            if (IndexWriter.IsLocked(directory))
            {
                //  如果索引目录被锁定（比如索引过程中程序异常退出），则首先解锁
                //  Lucene.Net在写索引库之前会自动加锁，在close的时候会自动解锁
                IndexWriter.Unlock(directory);
            }
            //Lucene的index模块主要负责索引的创建
            //  创建向索引库写操作对象  IndexWriter(索引目录,指定使用盘古分词进行切词,最大写入长度限制)
            //  补充:使用IndexWriter打开directory时会自动对索引库文件上锁
            //IndexWriter构造函数中第一个参数指定索引文件存储位置；
            //第二个参数指定分词Analyzer，Analyzer有多个子类，
            //然而其分词效果并不好，这里使用的是第三方开源分词工具盘古分词；
            //第三个参数表示是否重新创建索引，true表示重新创建（删除之前的索引文件），
            //最后一个参数指定Field的最大数目。
            IndexWriter writer = null;

            try
            {
                writer = new IndexWriter(directory, new PanGuAnalyzer(), true,
                    IndexWriter.MaxFieldLength.UNLIMITED);

                var txtPath = Directory.GetCurrentDirectory() + "/Upload/Articles";
                //String s_txtPath = txtPath.ToString();
                //string[] files = Directory.GetFiles(txtPath);
                FileInfo[] files = new DirectoryInfo(txtPath).GetFiles("", SearchOption.AllDirectories);
                // Directory.CreateDirectory(txtPath).GetFiles
                //File file = new File("D:\\360Downloads");
                //String s_txtPath = txtPath.ToString();
                // File[] files = new File(s_txtPath)
                //File file = new File(s_txtPath);
                for (int i = 0; i < files.Length; i++)
                {
                    //Document document = new Document();
                    Lucene.Net.Documents.Document document = null;
                    if (files[i].Name.EndsWith(".txt"))
                    {
                        document = new Lucene.Net.Documents.Document();
                        var content = System.IO.File.ReadAllText(files[i].FullName, Encoding.Default);
                        //  每个Document可以有自己的属性（字段），所有字段名都是自定义的，值都是string类型
                        //  Field.Store.YES不仅要对文章进行分词记录，也要保存原文，就不用去数据库里查一次了
                        document.Add(new Lucene.Net.Documents.Field("Title", files[i].Name, Lucene.Net.Documents.Field.Store.YES, Lucene.Net.Documents.Field.Index.NOT_ANALYZED));
                        //  需要进行全文检索的字段加 Field.Index. ANALYZED
                        //  Field.Index.ANALYZED:指定文章内容按照分词后结果保存，否则无法实现后续的模糊查询 
                        //  WITH_POSITIONS_OFFSETS:指示不仅保存分割后的词，还保存词之间的距离
                        document.Add(new Field("FileAddress", files[i].FullName.Replace(Directory.GetCurrentDirectory(), ""), Field.Store.YES, Field.Index.NOT_ANALYZED));
                        document.Add(new Lucene.Net.Documents.Field("Content", content, Lucene.Net.Documents.Field.Store.YES, Lucene.Net.Documents.Field.Index.ANALYZED, Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));
                        writer.AddDocument(document);

                    }
                    else if (files[i].Name.EndsWith(".pdf"))
                    {
                        document = getPDF(files[i]);
                        writer.AddDocument(document);
                    }
                    else if (files[i].Name.EndsWith(".doc") || files[i].Name.EndsWith(".docx"))
                    {
                        document = getDOC(files[i]);
                        writer.AddDocument(document);
                    }
                    else if (files[i].Name.EndsWith(".ppt") || files[i].Name.EndsWith(".pptx"))
                    {
                        document = getPPT(files[i]);
                        writer.AddDocument(document);
                    }
                    else if (files[i].Name.EndsWith(".xls") || files[i].Name.EndsWith(".xlsx"))
                    {
                        document = getXLS(files[i]);
                        writer.AddDocument(document);
                    }


                }
            }
            catch (Exception ex)
            {

                response.SetFailed(ex.Message);
                return Ok(response);
            }
            finally
            {
                if (writer != null)
                    writer.Close(); // Close后自动对索引库文件解锁
                if (directory != null)
                    directory.Close(); //  不要忘了Close，否则索引结果搜不到
            }
            response.SetSuccess("索引创建完毕");
            return Ok(response);

        }

        /// <summary>
        /// 搜索
        /// </summary>
        /// <returns></returns>
        [HttpGet]

        public object Search(string keyWord, int pageIndex, int pageSize)
        {
            //HttpContext.RequestServices.GetService()
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            string indexPath = Directory.GetCurrentDirectory() + "/LuceneIndex";
            FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NoLockFactory());
            IndexReader reader = IndexReader.Open(directory, true);
            //创建IndexSearcher准备进行搜索。
            IndexSearcher searcher = new IndexSearcher(reader);
            // 查询条件
            keyWord = GetKeyWordsSplitBySpace(keyWord, new PanGuTokenizer());
            //创建QueryParser查询解析器。用来对查询语句进行语法分析。
            //QueryParser调用parser进行语法分析，形成查询语法树，放到Query中。
            QueryParser msgQueryParser = new QueryParser(Lucene.Net.Util.Version.LUCENE_29, "Content", new PanGuAnalyzer(true));
            Query msgQuery = msgQueryParser.Parse(keyWord);
            //TopScoreDocCollector:盛放查询结果的容器
            //numHits 获取条数
            TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);
            //IndexSearcher调用search对查询语法树Query进行搜索，得到结果TopScoreDocCollector。
            // 使用query这个查询条件进行搜索，搜索结果放入collector
            searcher.Search(msgQuery, null, collector);
            // 从查询结果中取出第n条到第m条的数据
            ScoreDoc[] docs = collector.TopDocs(0, 1000).scoreDocs;
            stopwatch.Stop();
            // 遍历查询结果
            List<ReturnModel> resultList = new List<ReturnModel>();
            var pm = new Page<ReturnModel>
            {
                PageIndex = pageIndex,
                PageSize = pageSize,
                TotalRows = docs.Length
            };
            pm.TotalPages = pm.TotalRows / pageSize;
            if (pm.TotalRows % pageSize != 0) pm.TotalPages++;
            for (int i = (pageIndex - 1) * pageSize; i < pageIndex * pageSize && i < docs.Length; i++)
            {
                var doc = searcher.Doc(docs[i].doc);
                var content = HighlightHelper.HighLight(keyWord, doc.Get("Content"));
                var result = new ReturnModel
                {
                    Title = doc.Get("Title"),
                    Content = content,
                    FileAddress = HttpContext.Request.Scheme+"://"+ HttpContext.Request.Host.Value+ doc.Get("FileAddress").Replace("\\","/"),//注意这里拼接
                    Count = Regex.Matches(content, "<font").Count
                };
                resultList.Add(result);
            }

            pm.LsList = resultList;
            var elapsedTime = stopwatch.ElapsedMilliseconds + "ms";
            var list = new { list = pm, ms = elapsedTime };
            return list;
        }

        public static Lucene.Net.Documents.Document getPDF(FileInfo file)
        {
            Document document = new Document();
            PdfReader pdfReader = new PdfReader(file.FullName);
            int numberOfPages = pdfReader.NumberOfPages;
            string content = string.Empty;


            for (int i = 1; i <= numberOfPages; ++i)
            {
                content += PdfTextExtractor.GetTextFromPage(pdfReader, i);
            }
            pdfReader.Close();
            //content = content.Replace("\r", string.Empty).Replace("\n", string.Empty).Replace("\t", string.Empty).Trim();
            document.Add(new Lucene.Net.Documents.Field("Title", file.Name, Field.Store.YES, Field.Index.NOT_ANALYZED));
            document.Add(new Field("FileAddress", file.FullName.Replace(Directory.GetCurrentDirectory(), ""), Field.Store.YES, Field.Index.NOT_ANALYZED));
            document.Add(new Field("Content", content, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
            return document;
        }
        public static Lucene.Net.Documents.Document getDOC(FileInfo file)
        {

            Document document = new Document();

            Spire.Doc.Document doc = new Spire.Doc.Document();
            doc.LoadFromFile(file.FullName);
            StringBuilder sb = new StringBuilder();
            foreach (Section section in doc.Sections)
            {
                //遍历section中每一个段落
                foreach (Paragraph paragraph in section.Paragraphs)
                {
                    //提取Word的每一行文字存入StringBuilder对象
                    sb.AppendLine(paragraph.Text);
                }
            }
            document.Add(new Field("Title", file.Name, Field.Store.YES, Field.Index.NOT_ANALYZED));
            document.Add(new Field("FileAddress", file.FullName.Replace(Directory.GetCurrentDirectory(), ""), Field.Store.YES, Field.Index.NOT_ANALYZED));
            document.Add(new Field("Content", sb.ToString(), Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
            return document;
        }

        public static Lucene.Net.Documents.Document getPPT(FileInfo file)
        {

            Document document = new Document();
            Spire.Presentation.Presentation ppt = new Spire.Presentation.Presentation();
            //Spire.Doc.Document doc = new Spire.Doc.Document();

            ppt.LoadFromFile(file.FullName);
            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < ppt.Slides.Count; i++)
            {
                for (int j = 0; j < ppt.Slides[i].Shapes.Count; j++)
                {
                    if (ppt.Slides[i].Shapes[j] is IAutoShape)
                    {
                        IAutoShape shape = ppt.Slides[i].Shapes[j] as IAutoShape;
                        if (shape.TextFrame != null)
                        {
                            foreach (TextParagraph tp in shape.TextFrame.Paragraphs)
                            {
                                sb.Append(tp.Text + Environment.NewLine);
                            }
                        }

                    }
                }
            }
            document.Add(new Field("Title", file.Name, Field.Store.YES, Field.Index.NOT_ANALYZED));
            document.Add(new Field("FileAddress", file.FullName.Replace(Directory.GetCurrentDirectory(), ""), Field.Store.YES, Field.Index.NOT_ANALYZED));
            document.Add(new Field("Content", sb.ToString(), Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
            return document;
        }
        public static Lucene.Net.Documents.Document getXLS(FileInfo file)
        {

            Document document = new Document();
            Workbook workbook = new Workbook();
            if (file.FullName.EndsWith(".xls"))
            {
                workbook.LoadFromFile(file.FullName, ExcelVersion.Version97to2003);
            }
            else
            {
                workbook.LoadFromFile(file.FullName, ExcelVersion.Version2016);
            }


            //获取第一张sheet
            Worksheet sheet = workbook.Worksheets[0];

            //设置range范围
            CellRange range = sheet.Range[sheet.FirstRow, sheet.FirstColumn, sheet.LastRow, sheet.LastColumn];

            //输出数据, 同时输出列名以及公式值
            DataTable dt = sheet.ExportDataTable(range, true, true);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                for (int j = 0; j < dt.Columns.Count; j++)
                {

                    sb.Append(dt.Rows[i][j].ToString() + Environment.NewLine);

                }
            }
            document.Add(new Field("Title", file.Name, Field.Store.YES, Field.Index.NOT_ANALYZED));
            document.Add(new Field("FileAddress", file.FullName.Replace(Directory.GetCurrentDirectory(), ""), Field.Store.YES, Field.Index.NOT_ANALYZED));
            document.Add(new Field("Content", sb.ToString(), Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
            return document;
        }
        /// <summary>
        /// 盘古分词
        /// </summary>
        /// <param name="words"></param>
        /// <returns></returns>
        [HttpGet]
        [Route("standard")]
        public object Standard(string words)
        {
            var str = Participle.PanGu(words);
            return str;
        }
      
        /// <summary>
        /// 对关键字进行盘古分词处理
        /// </summary>
        /// <param name="keywords"></param>
        /// <param name="ktTokenizer"></param>
        /// <returns></returns>
        private static string GetKeyWordsSplitBySpace(string keywords, PanGuTokenizer ktTokenizer)
        {
            StringBuilder result = new StringBuilder();
            ICollection<WordInfo> words = ktTokenizer.SegmentToWordInfos(keywords);

            foreach (WordInfo word in words)
            {
                if (word == null)
                {
                    continue;
                }
                result.AppendFormat("{0}^{1}.0 ", word.Word, (int)Math.Pow(3, word.Rank));
            }
            return result.ToString().Trim();
        }

    }
}